using System;

namespace RapidHDL
{
	/// <summary>
	/// Summary description for Clock.
	/// </summary>
	public class ClockComponent : Component 
	{

        public delegate void ClockEdgeEvent(bool pblnRisingEdge);

        System.Collections.ArrayList oRegisters;
        System.Collections.ArrayList oRisingEdgeEvents;
        System.Collections.ArrayList oFallingEdgeEvents;

        public NodeVector ClockIn;
		public NodeVector ClockOut;

		public ClockComponent(Component poParentComponent, string psName) 
			: base (poParentComponent,psName)
		{
            oRegisters = new System.Collections.ArrayList();
            oRisingEdgeEvents = new System.Collections.ArrayList();
            oFallingEdgeEvents = new System.Collections.ArrayList();

            ClockIn = this.CreateNodeVector("CLK_I", 1, NodeFlowType.Sink);
            ClockOut = this.CreateNodeVector("CLK_O", 1, NodeFlowType.Source);
		}
		
		public void LinkRegister(RegisterComponent oRegisterComponent)
		{
            if (!oRegisters.Contains(oRegisterComponent))
            {
                oRegisters.Add(oRegisterComponent);
                if (oRegisterComponent.RisingEdge)
                    oRisingEdgeEvents.Add(new ClockEdgeEvent(oRegisterComponent.ClockEdgeEvent));
                else
                    oFallingEdgeEvents.Add(new ClockEdgeEvent(oRegisterComponent.ClockEdgeEvent));
            }
		}

        public void RisingEdge()
        {
            foreach (ClockEdgeEvent oEdgeEvent in oRisingEdgeEvents)
                oEdgeEvent(true);
        }

        public void FallingEdge()
        {
            foreach (ClockEdgeEvent oEdgeEvent in oFallingEdgeEvents)
                oEdgeEvent(false);
        }

        public void ToggleClock()
        {
            Node nClock = (Node)ClockOut.Nodes[0];
            if (nClock.NodeState == NodeState.High)
            {
                nClock.NodeState = NodeState.Low;
                RisingEdge();
            }
            else
            {
                nClock.NodeState = NodeState.High;
                FallingEdge();
            }
        }

        public override bool TransformStructureToVerilog()
        {
            string sVerilog = "assign CLK_O = CLK_I;";
            ComponentVerilog.WriteVerilogText(sVerilog, 1);
            return true;
        }
	}
}
